Add the WolfCertTransport to extend the portability on embedded platforms - #15
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors wolfCert’s HTTP/TLS I/O so the library no longer assumes BSD sockets: all network traffic (including TLS records) is routed through a new WolfCertTransport vtable, with the POSIX sockets implementation moved into a removable src/net_posix.c. This improves portability for embedded/RTOS targets while keeping the default POSIX path as the built-in transport.
Changes:
- Introduces
WolfCertTransportand threads it through request/session/server configs; deprecates the fd-basedconnect_cb. - Removes POSIX syscalls/headers from core HTTP and CSR paths by adding a CBIO bridge for wolfSSL and a portable IP-literal parser.
- Adds build/config gating for “platform pieces” (built-in transport and POSIX store), updates tests/CI/docs, and adds
WOLFCERT_ERR_CONN_CLOSED.
Reviewed changes
Copilot reviewed 38 out of 38 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| wolfcert/types.h | Adds WolfCertTransport and extends config structs with transport. |
| wolfcert/options.h.in | Adds generated feature macros for platform gating. |
| wolfcert/http.h | Exposes transport in public HTTP request/session configs and updates docs/comments. |
| wolfcert/errors.h | Adds WOLFCERT_ERR_CONN_CLOSED. |
| wolfcert/check_config.h | Enforces HAVE_SNI unless WOLFCERT_NO_SNI is defined. |
| src/http.c | Core refactor: transport-owned I/O, wolfSSL CBIO bridge, locale-stable header comparisons, legacy adapter. |
| src/net_posix.c | Implements built-in POSIX WolfCertTransport + legacy connect adapter. |
| src/internal.h | Declares wolfcert_parse_ip and transport helpers/externs. |
| src/internal.c | Implements portable IPv4/IPv6 literal parsing. |
| src/csr.c | Switches SAN iPAddress encoding to wolfcert_parse_ip (removes inet_pton). |
| src/store.c | Compile-gates POSIX store backend and provides stubs when disabled. |
| src/errors.c | Adds strerror text for WOLFCERT_ERR_CONN_CLOSED. |
| src/est/est_client.c | Propagates transport from server cfg into HTTP request/session configs. |
| src/scep/scep_client.c | Propagates transport from server cfg into HTTP request/session configs. |
| cli/wolfcert_client.c | Drops explicit connect_cb use so CLI uses the default built-in transport. |
| tests/unit/test_transport.c | New unit tests covering scripted transport behavior and edge cases. |
| tests/unit/test_http.c | Adds conflict test for connect_cb + transport; marks skip when builtin transport is off. |
| tests/unit/test_store.c | Skips POSIX store tests when POSIX store is compiled out. |
| tests/unit/test_parse_negative.c | Adds negative/positive coverage for new IP literal parser. |
| tests/unit/test_est.c | Marks skip when builtin transport is off. |
| tests/unit/test_csr.c | Adds CSR SAN iPAddress assertions (v4/v6). |
| tests/integration/test_tls_http.c | Marks skip when builtin transport is off. |
| tests/CMakeLists.txt | Adds test_transport, gates socket tests on builtin transport, sets skip return codes. |
| CMakeLists.txt | Adds options for POSIX store / builtin transport and gates sources accordingly. |
| configure.ac | Adds autoconf flags for builtin transport / POSIX store and emits options.h macros. |
| Makefile.am | Gates src/net_posix.c and socket-driven tests on builtin transport. |
| examples/user_settings.h.example | Documents the new platform feature macros for user-settings builds. |
| scripts/ci/build-wolfssl.sh | Enables SNI in the CI wolfSSL build. |
| scripts/ci/freestanding-user_settings.h | Adds a no-sockets/no-files freestanding settings bundle for CI gating. |
| scripts/ci/compile-freestanding.sh | New compile-only “no POSIX headers” gate for portable sources. |
| .github/workflows/pr.yml | Adds CI matrix row for “platform pieces off” and a freestanding ARM compile job. |
| .github/workflows/nightly.yml | Adds nightly run for “platform pieces off” build. |
| README.md | Documents transport vtable portability in feature overview and enables SNI in example configure line. |
| docs/ARCHITECTURE.md | Adds full transport contract/bridge documentation. |
| docs/EMBEDDED.md | Documents targets without sockets/filesystem and new build flags/macros. |
| docs/MIGRATING-FROM-WOLFSCEP.md | Updates migration guidance to use WolfCertTransport instead of connect_cb. |
| docs/CI.md | Documents new CI gates (cmake-no-builtin-transport, no-posix-arm). |
| CLAUDE.md | Updates canonical wolfSSL configure line to include --enable-sni. |
Suppressed comments (1)
src/http.c:502
- wolfcert_cbio_send collapses WOLFCERT_ERR_WANT_READ into WOLFSSL_CBIO_ERR_WANT_WRITE. A transport write() can legitimately return WANT_READ in non-blocking mode; mapping it to WANT_WRITE makes wolfSSL report the wrong condition and breaks event-loop readiness handling.
switch (r) {
case WOLFCERT_ERR_WANT_READ:
case WOLFCERT_ERR_WANT_WRITE:
return WOLFSSL_CBIO_ERR_WANT_WRITE;
case WOLFCERT_ERR_CONN_CLOSED:
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #15
Scan targets checked: wolfcert-bugs, wolfcert-src
Findings: 6
6 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
43e1e76 to
ba1aec2
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #15
Scan targets checked: none
Failed targets: wolfcert-bugs, wolfcert-src
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #15
Scan targets checked: wolfcert-bugs, wolfcert-src
Findings: 4
4 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
ba1aec2 to
c48b404
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #15
Scan targets checked: wolfcert-bugs, wolfcert-src
Findings: 4
4 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
c48b404 to
d154d01
Compare
5dbba8a to
31df8f3
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #15
Scan targets checked: wolfcert-bugs, wolfcert-src
Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
The issues are solved
|
Hi @Frauschi , |
Frauschi
left a comment
There was a problem hiding this comment.
Read through the transport series. The shape is right: making the POSIX path one instance of the vtable instead of a privileged path is the correct call, and routing TLS records through the same read/write pair - so the default build exercises the bridge on every test - is the detail that makes it trustworthy rather than just plausible.
One blocker. The two new WOLFCERT_HAVE_* platform gates have no check_config.h guard, so a WOLFCERT_USER_SETTINGS integrator carrying a user_settings.h written before this PR gets a library that compiles and links clean and then fails every request at runtime with no diagnostic. CI can't see it because the header-only job copies the updated example.
The rest is mostly contract gaps in src/net_posix.c. That file is the one every port will copy, so the errno mapping and the timeout_ms > 0 handling are worth getting right there rather than in each integrator's glue. Beyond that: dial() doesn't validate what connect returns, and the session_fd comments in est.h / scep.h still promise a descriptor that a custom transport cannot give.
Nothing here re-opens the SIGPIPE, CBIO-direction or deferred-transport-test threads - those are already answered.
- WolfCertTransport (connect/read/write/disconnect/ctx) and WOLFCERT_ERR_CONN_CLOSED, settable on the three config structs. - src/net_posix.c carries the built-in POSIX instance. - http.c moves every byte through the vtable and bridges wolfSSL's CBIO onto it, so TLS records and plain HTTP share one path.
- ARCHITECTURE section 4.6 carries the vtable contract, and the session_fd contract narrows to the built-in transport. - scripts/ci/compile-freestanding.sh compiles the portable sources for a Cortex-M4 with no POSIX headers; check_config.h requires HAVE_SNI.
31df8f3 to
9b9cd67
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #15
Scan targets checked: wolfcert-bugs, wolfcert-src
Fenrir result: Approved ✅
No new issues found in the changed files.
Advisory only — this automated result does not count as a GitHub approval.
- net_posix.c calls recv and send directly rather than wolfIO_Recv and wolfIO_Send, which link only under USE_WOLFSSL_IO. - WolfCertConnectFn and the connect_cb / connect_ctx fields are gone; dial() takes only the transport. - The three config structs hold a WolfCertTransport by value, copied when the connection opens, and wolfcert_transport_fd() replaces wolfcert_transport_is_fd_backed(). - read and write take two timeout_ms modes, 0 and negative. ARCHITECTURE 4.6 also states that honouring len is the transport's responsibility, and that wolfcert_http_session_fd() returns an O_NONBLOCK descriptor. - Makefile.am keeps the conditional test_net entry with check_PROGRAMS.
9b9cd67 to
d6b57ac
Compare
|
Hi @Frauschi , |
Problem
wolfCert could not run on a stack without BSD sockets. It had a hook for
opening a connection (
connect_cb, shaped as a file descriptor) but keptownership of the socket lifecycle:
close,fcntl,sendandrecvsatinline in
src/http.c, and the raw descriptor went into wolfSSL throughwolfSSL_set_fd, which overwrites any custom CBIO context the application hadinstalled.
src/csr.candsrc/store.calso required POSIX headers.Fix (
src/http.c)A
WolfCertTransportvtable now owns every byte on the wire, TLS recordsincluded:
Callers embed it by value in the three config structs. Leaving it zeroed
selects the built-in POSIX instance; a half-filled one is
WOLFCERT_ERR_BAD_ARG.It is copied when the connection opens, so only
ctxmust outlive it.src/net_posix.ccarries the built-in POSIX instance, making it oneimplementation of the vtable rather than a privileged path. It calls
recvand
senddirectly and depends on none of wolfSSL's optionalwolfIO_Send/wolfIO_Recvhelpers, which are absent underWOLFSSL_USER_IO,MICRIUM,WOLFSSL_CONTIKIandWOLFSSL_NO_SOCK.read/writepair, andwolfSSL_set_fdis gone from the client. The bridgeis on every path including the default one, so the existing round-trip suite
exercises it.
src/http.cperforms no syscall and includes no POSIX header. Neither dosrc/csr.c, where a local IP-literal parser replacesinet_pton, orsrc/store.c, whose file backend is now compile-gated.Additions:
WolfCertTransport, plus atransportfield on the three config structswolfcert/types.h,wolfcert/http.hWOLFCERT_ERR_CONN_CLOSED(-16)wolfcert/errors.hWOLFCERT_HAVE_BUILTIN_TRANSPORT,WOLFCERT_HAVE_POSIX_STOREwolfcert/options.hBreaking changes — recompile, do not just relink:
WolfCertConnectFnand theconnect_cb/connect_ctxfields are goneWolfCertTransport;wolfcert_posix_connect()stays public so a customconnectcan open its TCP leg with ittransportis embedded by value, so the config structs grow.transport = &tbecomes.transport = tHAVE_SNIis now required--enable-sni, or defineWOLFCERT_NO_SNIwhen every endpoint serves a single certificateuser_settings.hbuild must state each platform gateWOLFCERT_HAVE_BUILTIN_TRANSPORT/_POSIX_STORE, or the matchingWOLFCERT_NO_**_session_fd()returns-1under a caller-supplied transportO_NONBLOCK; a blocking session's used not to beTests
tests/unit/test_transport.cdrives the whole HTTP path through a scriptedtransport with no sockets, threads or TLS, so it runs in every build
configuration: handle
0is a valid handle,disconnectruns exactly once,the vtable is copied so the caller's may die with its frame, a half-filled
vtable is rejected before anything is dialled while a zeroed one takes the
built-in transport, the parser survives a byte-at-a-time feed, and a body may
end at
CONN_CLOSED. A transport that breaks the contract — returning0forEOF, a positive
connectcode, or more bytes than were requested — is refusedrather than trusted.
Verification
-Werror. 27 of 27 tests pass on thedefault configuration, and 11 of 11 with 3 skipped when the built-in
transport and POSIX store are compiled out.
guards that matter: removing the over-count check reproduces a
stack-buffer-overflow, and borrowing the vtable instead of copying itreproduces a
stack-use-after-scope.no-posix-armgate compiles all 15 portable sources for a Cortex-M4against wolfSSL headers only, and a
user_settings.hnaming neither platformgate now fails at
check_config.hinstead of silently losing networking.Not in this PR
transport.connect. It has no would-block vocabulary, so sessionsetup blocks even under
cfg.nonblocking. Changing it is a vtable contractchange and is better done deliberately than folded in here.
WOLFCERT_NO_POSIX_STOREstub and forwolfcert_strerror'snew code. Both guard code that cannot regress silently — a missing stub is a
link error the existing gated CI job already catches.
and independent of this refactor; it sits on its own branch.